package pl.jtb.ctl.tabory.ui.boe.ui.ve;

import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;

import pl.jtb.ctl.tabory.dao.api.services.IVagonService;
import pl.jtb.ctl.tabory.dao.data.vo.CompositionVO;
import pl.jtb.ctl.tabory.dao.data.vo.VagonVO;
import pl.jtb.ctl.tabory.dao.impl.mybatis.servicemanager.ServiceManager;
import pl.jtb.ctl.tabory.ui.boe.osgi.Activator;
import pl.jtb.ctl.tabory.ui.boe.selection.VagonSelection;
import pl.jtb.ctl.tabory.ui.editors.AbstractMasterSectionPart;
import pl.jtb.ctl.tabory.ui.editors.EditorStateSL;
import pl.jtb.ctl.tabory.ui.osgi.UiBundleActivator;
import pl.jtb.ctl.tabory.ui.selection.ISelectionListener;

public class VagonMasterSectionPart extends AbstractMasterSectionPart<VagonSelection> {

    private final static Logger logger = Logger.getLogger(VagonMasterSectionPart.class);

    public enum AvailableColumnsSL {
        COLUMN_VAGON_NAME, COLUMN_COMPOSITION_NAME, COLUMN_DISTANCE_CORRECTED
    };

    private boolean isToolBarVisible;
    private boolean isFilterVisible;

    private Set<AvailableColumnsSL> columnSet;

    private FilterCompositionId filterCompositionId;
    private FilterVagonId filterVagonId;
    private Text filterVagonName;
    private Text filterVagonComposition;
    private Section filterSection;

    private ISelectionListener<VagonSelection> selectionListener;

    public VagonMasterSectionPart(Composite parent, FormToolkit toolkit, int style, String sectionName, boolean isToolBarVisible, boolean isFilterVisible, Set<AvailableColumnsSL> columnSet) {
        super(parent, toolkit, style, sectionName);
        this.isFilterVisible = isFilterVisible;
        this.isToolBarVisible = isToolBarVisible;
        this.columnSet = columnSet;
        initGui(parentSection, toolkit);
        postInitGui(parentSection, toolkit);
        initActions();
    }

    @Override
    public VagonSelection getSelection() {
        logger.debug("Retriev selection: " + selection.toString());
        return selection;
    }

    @Override
    public void setSelection(VagonSelection selection) {
        logger.debug("Setting selection: " + selection.toString());
        this.selection = selection;
        refreshToolBar();
        if (selection.getEditorState().equals(EditorStateSL.CLEAN)) {
            setEnabled(true);
        } else {
            setEnabled(false);
        }
        tableViewer.setInput(selection.getListVagons());
    }

    @Override
    public void addSelectionListener(ISelectionListener<VagonSelection> listner) {
        this.selectionListener = listner;
    }

    @Override
    public void removeSelectionListener(ISelectionListener<VagonSelection> listner) {
    }

    @Override
    protected void initGui(Section parentSection, FormToolkit toolkit) {
        toolBar = getToolBar(parentSection, toolkit);
        parentSection.setTextClient(toolBar);
        toolBar.setVisible(isToolBarVisible);

        Composite container = toolkit.createComposite(parentSection);
        GridLayoutFactory.fillDefaults().numColumns(1).applyTo(container);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(container);

        parentSection.setClient(container);
        tableViewer = new TableViewer(container, SWT.BORDER | SWT.FULL_SELECTION);
        table = tableViewer.getTable();
        table.setHeaderVisible(true);
        toolkit.paintBordersFor(table);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(table);

        if (columnSet.contains(AvailableColumnsSL.COLUMN_VAGON_NAME)) {
            TableColumn columnVagonId = new TableViewerColumn(tableViewer, SWT.NONE).getColumn();
            columnVagonId.setWidth(100);
            columnVagonId.setText(Activator.getMessage("vagons.editor.master.table.vagonname"));
        }

        if (columnSet.contains(AvailableColumnsSL.COLUMN_COMPOSITION_NAME)) {
            TableColumn columnCompositionId = new TableViewerColumn(tableViewer, SWT.NONE).getColumn();
            columnCompositionId.setWidth(100);
            columnCompositionId.setText(Activator.getMessage("vagons.editor.master.table.compositionname"));
        }

        if (columnSet.contains(AvailableColumnsSL.COLUMN_DISTANCE_CORRECTED)) {
            TableColumn columnCompositionId = new TableViewerColumn(tableViewer, SWT.NONE).getColumn();
            columnCompositionId.setWidth(150);
            columnCompositionId.setText(Activator.getMessage("vagons.editor.master.table.distancecorrected"));
        }

        tableViewer.setLabelProvider(new TableLabelProvider());
        tableViewer.setContentProvider(new TableContentProvider());
        tableViewer.setSorter(new TableViewerSorter());
        tableViewer.addFilter(filterCompositionId = new FilterCompositionId());
        tableViewer.addFilter(filterVagonId = new FilterVagonId());

        filterSection = toolkit.createSection(container, Section.TWISTIE | Section.TITLE_BAR);
        GridLayoutFactory.fillDefaults().numColumns(1).margins(5, 5).applyTo(filterSection);
        toolkit.paintBordersFor(filterSection);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, false).applyTo(filterSection);

        Composite filterComposite = toolkit.createComposite(filterSection);
        filterSection.setText(UiBundleActivator.getMessage("common.filter"));
        toolkit.paintBordersFor(filterComposite);
        filterSection.setClient(filterComposite);
        GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(filterComposite);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, false).applyTo(filterComposite);

        Label filterVagonNameLabel = toolkit.createLabel(filterComposite, Activator.getMessage("vagons.editor.filter.vagonname"));
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(filterVagonNameLabel);
        filterVagonName = toolkit.createText(filterComposite, "");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(100, SWT.DEFAULT).grab(true, true).applyTo(filterVagonName);
        Label filterVagonCompositionLabel = toolkit.createLabel(filterComposite, Activator.getMessage("vagons.editor.filter.compositionname"));
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(filterVagonCompositionLabel);
        filterVagonComposition = toolkit.createText(filterComposite, "");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(100, SWT.DEFAULT).grab(true, true).applyTo(filterVagonComposition);
        toolkit.adapt(filterComposite, true, true);

        filterSection.setVisible(isFilterVisible);
    }

    public void hideFilterComposite() {
        filterSection.setExpanded(false);
    }

    public void clearFilters() {
        filterCompositionId.setPattern("");
        filterVagonId.setPattern("");
        tableViewer.refresh();
    }

    @Override
    public void setEnabled(boolean isEnabled) {
        super.setEnabled(isEnabled);
        filterSection.setEnabled(isEnabled);
    }

    @Override
    protected void postInitGui(Section parentSection, FormToolkit toolkit) {
    }

    @Override
    protected void initActions() {
        filterVagonComposition.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                filterCompositionId.setPattern(filterVagonComposition.getText());
                tableViewer.refresh();
            }
        });
        filterVagonName.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                filterVagonId.setPattern(filterVagonName.getText());
                tableViewer.refresh();
            }
        });
        toolItemNew.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                selection.setEditorState(EditorStateSL.NEW);
                selection.setSelectedVagon(null);
                selectionListener.selectionChanged(selection);
            }
        });
        toolItemEdit.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                selection.setEditorState(EditorStateSL.EDITING);
                selectionListener.selectionChanged(selection);
            }
        });
        toolItemDelete.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    IVagonService vagonService = ServiceManager.getInstance().getVagonService();
                    VagonVO selectedVagon = selection.getSelectedVagon();
                    boolean openConfirm = MessageDialog.openConfirm(getSection().getShell(), Activator.getMessage("vagons.editor.questions.delete.title"), Activator.getMessage("vagons.editor.questions.delete.message"));
                    if (openConfirm) {
                        vagonService.deleteVagon(selectedVagon);
                        selection.setListVagons(vagonService.getListAllVagons());
                        selection.setSelectedVagon(null);
                        selectionListener.selectionChanged(selection);
                    }
                } catch (Exception ex) {
                    logger.error(ex.getMessage(), ex);
                }
            }
        });
        tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                if (selectionListener != null) {
                    logger.debug("Table selection changed");
                    IStructuredSelection tableSelection = (IStructuredSelection) event.getSelection();
                    VagonVO selectedVagon = (VagonVO) tableSelection.getFirstElement();
                    selection.setSelectedVagon(selectedVagon);
                    selectionListener.selectionChanged(selection);
                }
            }
        });
    }

    @Override
    protected void refreshToolBar() {
        if (selection.getSelectedVagon() == null) {
            toolItemNew.setEnabled(true);
            toolItemEdit.setEnabled(false);
            toolItemDelete.setEnabled(false);
        } else {
            toolItemNew.setEnabled(true);
            toolItemEdit.setEnabled(true);
            toolItemDelete.setEnabled(true);
        }
    }

    private class TableLabelProvider extends LabelProvider implements ITableLabelProvider {

        public TableLabelProvider() {
            super();
        }

        @Override
        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        @Override
        public String getColumnText(Object element, int columnIndex) {
            VagonVO vagon = (VagonVO) element;
            switch (columnIndex) {
                case 0:
                    return vagon.getInternalId();
                case 1:
                    CompositionVO compositionForVagon = selection.getCompositionForVagon(vagon);
                    if (compositionForVagon != null) {
                        return compositionForVagon.getInternalId();
                    } else {
                        return "---";
                    }
                case 2: {
                    Double distance = vagon.getDistance();
                    Double revisionCorrection = vagon.getRevisionCorrection();
                    if (distance == null) {
                        distance = new Double(0.0);
                    }
                    if (revisionCorrection == null) {
                        revisionCorrection = new Double(0.0);
                    }
                    return String.valueOf(distance - revisionCorrection);
                }
                default:
                    return "";
            }
        }

    }

    private static class TableContentProvider implements IStructuredContentProvider {

        @Override
        public void dispose() {
        }

        @Override
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }

        @Override
        @SuppressWarnings("unchecked")
        public Object[] getElements(Object inputElement) {
            List<VagonVO> listVagons = (List<VagonVO>) inputElement;
            return listVagons.toArray();
        }

    }

    private static class TableViewerSorter extends ViewerSorter {
        @Override
        public int compare(Viewer viewer, Object e1, Object e2) {
            VagonVO v1 = (VagonVO) e1;
            VagonVO v2 = (VagonVO) e2;
            return super.compare(viewer, v1.getInternalId(), v2.getInternalId());
        }
    }

    private static class FilterVagonId extends ViewerFilter {

        private String patter;

        public void setPattern(final String pattern) {
            this.patter = pattern;
        }

        @Override
        public boolean select(Viewer viewer, Object parentElement, Object element) {
            if (patter == null || patter.length() == 0) {
                return true;
            }
            VagonVO vagon = (VagonVO) element;
            if (vagon.getInternalId().contains(patter)) {
                return true;
            }
            return false;
        }
    }

    private class FilterCompositionId extends ViewerFilter {

        private String patter;

        public FilterCompositionId() {
            super();
        }

        public void setPattern(final String pattern) {
            this.patter = pattern;
        }

        @Override
        public boolean select(Viewer viewer, Object parentElement, Object element) {
            if (patter == null || patter.length() == 0) {
                return true;
            }
            VagonVO vagon = (VagonVO) element;
            CompositionVO compositionForVagon = selection.getCompositionForVagon(vagon);
            if (compositionForVagon != null) {
                if (compositionForVagon.getInternalId().contains(patter)) {
                    return true;
                }
            }
            return false;
        }
    }

}
